home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / C / Code Resources / CDEF - DeBugger 2.0.2 / CDEF Routines.c < prev    next >
Encoding:
Text File  |  1995-10-19  |  56.6 KB  |  1,662 lines  |  [TEXT/KAHL]

  1. // I included some of my own drawing definitions.  Might want to check them out to understand them.
  2. // I know that my intent was to make this as simple as possible, but for me this is simple. Nothing
  3. // to complicated. Just some standard color definitions. Look at "MyColors.c" to see the functions.
  4.  
  5. // include files
  6.     #if !defined(powerc) && !defined (__powerc)
  7.     #include <SetUpA4.h>
  8.     #endif
  9.  
  10. // Prototypes
  11.     static pascal long     MyControl( short variation,  ControlHandle theControl, short message, long param );
  12.     void                 SetUpMyControl( CntlParam theParam );
  13.     void                DrawMyControl( ControlHandle theControl, short part );
  14.     short                TestMyControlParts( ControlHandle theControl, Point clickPnt );
  15.     void                InitMyControl( ControlHandle theControl );
  16.     void                 DisposeMyControl( ControlHandle theControl );
  17.     void                FillCntlParameters( ControlHandle theControl, CntlParmPtr *param );
  18.     void                CalcMyThumbPosition( ControlHandle theControl, Rect *realThumbRect );
  19.     void                DrawMyArrow( short var, Rect theRect );
  20.     void                DragMyThumb( ControlHandle theControl, Point mousePnt );
  21.     void                DragMyControl( ControlHandle theControl, Point mousePnt );
  22.     void                 DrawMyThumb( ControlHandle theControl, Boolean var );
  23.     void                CalcMyThumbRgn( ControlHandle theControl, RgnHandle *param );
  24.     void                PositionMyCntl( ControlHandle theControl, Point mousePnt );
  25.     void                 ConvertPtToVal( ControlHandle theControl, Point newPoint, short *value );
  26.     void                DrawValueInThumb( ControlHandle theControl, long value );
  27.  
  28. // Globals
  29.     extern Main            myMain;        // declared in Window-Main.c
  30.  
  31. // Macros & defines
  32.     #define    MY_THUMB_LENGTH        32     // simply put, this is the length of our thumb indicator.
  33.     
  34. /******************************************************************************
  35.  
  36.   Your code resource function starts here.
  37.   
  38.   variation        - If you have varitions of this control and they were implemented
  39.                     in you code, then if the user specifies one you will recieve it here.
  40.                     Example: Code Resource ID * 16 + varition
  41.                     
  42.   theControl    - a handle leading to the control record.
  43.   
  44.   msg            - this will be a message from the application to tell you what it
  45.                     wants. It could be drawCntl, testCntl, etc.
  46.                     
  47.   param            - this is a 4-byte value that is dependent on the msg.
  48.                     Examples of some are below in the msg's.
  49.   
  50. *******************************************************************************/
  51. static pascal long    MyControl( short variation, ControlHandle theControl, short msg, long param )
  52. {
  53.     Point            mousePnt;
  54.     Boolean            test;
  55.  
  56.     
  57. #if !defined(powerc) && !defined (__powerc)        // Don't bother setting up registers if PowerPC
  58.     SetUpA4();
  59. #endif
  60.     
  61.     HLock( (Handle)theControl );
  62.     if( (**theControl).contrlData ) {
  63.     
  64.         HLock( (**theControl).contrlData );
  65.         
  66.     }
  67.         
  68.     // Use 'msg' to determine what the application is wanting our control to do.
  69.     
  70.     switch( msg )
  71.     {
  72.         //------------------------------------------------------------------------
  73.         //
  74.         //    drawCntl ( message = 0 )    IM:Macintosh ToolBox Essentials : Page 5-111
  75.         //
  76.         //     Draw the entire control or draw the part specified by LoWord( param ).
  77.         //     Be sure to check the control's hilite value. If your control has an
  78.         //     indicator or thumb and param = 129 you must erase the thumb from it's
  79.         //     current position and redraw it according to the control's new value. 
  80.         //    Do not draw anything if the control is invisible.
  81.         //
  82.         //  Return - A zero. (always)
  83.         //------------------------------------------------------------------------
  84.         case drawCntl:
  85.             if( (**theControl).contrlVis ==  255 ) {
  86.                 DrawMyControl( theControl, LoWord( param ) );
  87.             }
  88.             return( 0L );
  89.             break;
  90.             
  91.         //------------------------------------------------------------------------
  92.         //
  93.         //    testCntl ( message = 1 )    IM:Macintosh ToolBox Essentials : Page 5-112
  94.         //
  95.         //     Check to see if the mouse point is in the control's rect or not.
  96.         //     horizontal = LoWord( param )
  97.         //     vertical   = HiWord( param )
  98.         //    This would be the area you create your parts if you have multiple things on
  99.         //    your control. Like a thumb, arrows, pageUp, etc..
  100.         //
  101.         //    Return - The part code of the part that contains the mouse point.
  102.         //             Return zero if the mouse point is outside the part or
  103.         //             the control is inactive.
  104.         //------------------------------------------------------------------------
  105.         case testCntl:
  106.             // first extract the mouse position
  107.             mousePnt.h = LoWord( param );
  108.             mousePnt.v = HiWord( param );
  109.             
  110.             // now determine if the mouse click was within our cntl rect.
  111.             if( PtInRect( mousePnt, &(**theControl).contrlRect )) {
  112.             
  113.                 // the click was inside our control so now define what part it was in.
  114.                 return( TestMyControlParts( theControl, mousePnt ));
  115.                 
  116.             } else {
  117.             
  118.                 // the click wasn't within our control. Don't do anything.
  119.                 return( 0L );
  120.                 
  121.             }
  122.             break;
  123.             
  124.         //------------------------------------------------------------------------
  125.         //
  126.         //    calcCRgns ( message = 2 )    IM:Macintosh ToolBox Essentials : Page 5-112
  127.         //
  128.         //     For non System 7.x systems.  The low 3 bytes of param is a region handle.
  129.         //     ( 4 bytes for 32-bit systems ). Mask the high byte and update the region
  130.         //     to enclose the entire control. If the high bit is set then it's asking for
  131.         //  the thumb or indicator. If not just use the entire control.
  132.         //
  133.         //    Return - A zero. (always) Be sure to express the region in local coordinates.
  134.         //------------------------------------------------------------------------
  135.         case calcCRgns:
  136.             if(( param & 0x80000000 ) == 0 ) {
  137.             
  138.                 // calculate the entire control.
  139.                 RectRgn( (RgnHandle)(param & 0x00FFFFFF), &(**theControl).contrlRect );
  140.                 
  141.             } else {
  142.                 
  143.                 // calculate only the indicator.
  144.                 Rect        realThumbRect;
  145.                 
  146.                 // obtain the current thumb position
  147.                 CalcMyThumbPosition( theControl, &realThumbRect );
  148.                 RectRgn( (RgnHandle)(param & 0x00FFFFFF), &realThumbRect );
  149.             }
  150.             return( 0L );
  151.             break;
  152.             
  153.         //------------------------------------------------------------------------
  154.         //
  155.         //    initCntl ( message = 3 )    IM:Macintosh ToolBox Essentials : Page 5-113
  156.         //
  157.         //     Do any special inititailization, calculations or allocations here. For a
  158.         //    standard scroll bar you would normally allocate the space for a region to 
  159.         //    the control's rect and region handles for the parts and store them in the
  160.         //    'contrlData' field in the control's record.
  161.         //
  162.         //    Return - A zero. (always)
  163.         //------------------------------------------------------------------------
  164.         case initCntl:
  165.             InitMyControl( theControl );
  166.             return( 0L );
  167.             break;
  168.             
  169.         //------------------------------------------------------------------------
  170.         //
  171.         //    dispCntl ( message = 4 )    IM:Macintosh ToolBox Essentials : Page 5-113
  172.         //
  173.         //     Do any special disposal of your control here.
  174.         //
  175.         //    Return - A zero. (always)
  176.         //------------------------------------------------------------------------
  177.         case dispCntl:
  178.             DisposeMyControl( theControl );
  179.             return( 0L );
  180.             break;
  181.             
  182.         //------------------------------------------------------------------------
  183.         //
  184.         //    posCntl ( message = 5 )        IM:Macintosh ToolBox Essentials : Page 5-113
  185.         //
  186.         //     Redraw the thumb and update the control's value.
  187.         //     You use this wether you use default dragging or not.
  188.         //     horizontal = LoWord( param ) = horizontal offset in pixels to move your indicator
  189.         //     vertical   = HiWord( param ) = vertical offset in pixels to move your indicator
  190.         //
  191.         //    Return - A zero. (always)
  192.         //------------------------------------------------------------------------
  193.         case posCntl:
  194.             // if you would like to test custom dragging comment out this function and
  195.             // un-comment the functions in 'dragCntl'. Leave return( 0L ) the same.
  196.             
  197.             mousePnt.h = LoWord( param );
  198.             mousePnt.v = HiWord( param );
  199.             PositionMyCntl( theControl, mousePnt );
  200.             
  201.             return( 0L );
  202.             break;
  203.             
  204.         //------------------------------------------------------------------------
  205.         //
  206.         //    thumbCntl ( message = 6 )    IM:Macintosh ToolBox Essentials : Page 5-114
  207.         //
  208.         //     When you recieve this message param points to a struct which you should
  209.         //     fill with thumb motion constraints. 
  210.         //
  211.         //     struct {
  212.         //        Rect    limitRect;    // on entry, top-left is the mouse point (local coord)
  213.         //                            // on exit this should be the same as the track rects
  214.         //                            // coordinates. ( take in account the thumb width )
  215.         //        Rect    slopRect;    // if the user drags outiside this rect
  216.         //                            // the control will stop dragging.
  217.         //        short    axis;        // The axis constraints the user may drag the control.
  218.         //                            // constants than can be used are:
  219.         //                            //         noConstraint = 0; ( no constraint )
  220.         //                            //        hAxisOnly     = 1; ( drag horizontal only )
  221.         //                            //        vAxisOnly     = 2; ( drag vertical only )
  222.         //
  223.         //    * these values are ignored if you use any custom dragging
  224.         //
  225.         //    Return - Just fill in the struct.
  226.         //------------------------------------------------------------------------
  227.         case thumbCntl:
  228.             FillCntlParameters( theControl, (CntlParmPtr*)¶m );
  229.             break;
  230.             
  231.         //------------------------------------------------------------------------
  232.         //
  233.         //    dragCntl ( message = 7 )    IM:Macintosh ToolBox Essentials : Page 5-114
  234.         //
  235.         //    If param = 0 then drag the entire control. If param = non-zero then
  236.         //    just drag the indicator or thumb. For default dragging just return
  237.         //    a 0 (zero). For custom dragging, follow the mouse around untill released
  238.         //    then handle the details and return a non-zero.
  239.         //    NOTE: If you do return a zero then you can ignore postCntl and thumbCntl.
  240.         //
  241.         //    Return - For default dragging, return a zero. If your return something else
  242.         //             then the control manager does not drag your control. But instead
  243.         //             relies on your custom drag procedure.
  244.         //------------------------------------------------------------------------
  245.         case dragCntl:
  246.             // if you would like to test these functions (custom dragging) remove
  247.             // the comments and comment out the functions in 'posCntl'
  248.             
  249.             //GetMouse( &mousePnt );
  250.             //DragMyThumb( theControl, param, mousePnt );
  251.             //return( 1 );
  252.             
  253.             return( 0L ); // comment out for custom dragging.
  254.             break;
  255.             
  256.         //------------------------------------------------------------------------
  257.         //
  258.         //    autoTrack ( message = 8 )    IM:Macintosh ToolBox Essentials : Page 5-115
  259.         //
  260.         //    This message will be sent if you specify -1 in the final parameter of
  261.         //    TrackControl() and the contrlAction of the control is also -1. If so,
  262.         //    LoWord( param ) will contain a part code and a handle to a routine
  263.         //    to take care of it. Basically an action procedure as set by the user.
  264.         //------------------------------------------------------------------------
  265.         case autoTrack:
  266.             break;
  267.                 
  268.         // The folowing messages are used only if the user is running System 7.x
  269.         // and when 32-bit addressing is enabled.
  270.         
  271.         //------------------------------------------------------------------------
  272.         //
  273.         //    calcCntlRgn ( message = 10 )    IM:Macintosh ToolBox Essentials : Page 5-111
  274.         //
  275.         //    This is essentially the same as calcCRgns except you do not have to
  276.         //    mask out the high byte of the region handle. Used only when 32-bit
  277.         //  addressing is on and running system 7.x. If running 24-bit addressing
  278.         //    calcCRgns will still be used.
  279.         //
  280.         //    Return - A zero (always) Be sure to express the region in local coordinates.
  281.         //------------------------------------------------------------------------
  282.         case calcCntlRgn:
  283.             RectRgn( (RgnHandle)param, &(**theControl).contrlRect );
  284.             return( 0L );
  285.             break;
  286.             
  287.         //------------------------------------------------------------------------
  288.         //
  289.         //    calcThumbRgn ( message = 11 )    IM:Macintosh ToolBox Essentials : Page 5-111
  290.         //
  291.         //    This is asking you to calculate your indicator or thumb's region. Used
  292.         //    only when 32-bit  adressing is on and running system 7.x. If running
  293.         //    24-bit addressing calcCRgns will still be used.
  294.         //
  295.         //    Return - A zero (always) Be sure to express the region in local coordinates.
  296.         //------------------------------------------------------------------------
  297.         case calcThumbRgn:
  298.             CalcMyThumbRgn( theControl, (RgnHandle*)¶m );
  299.             return( 0L );
  300.             break;
  301.     }
  302.     
  303.     HUnlock( (Handle)theControl );
  304.     if( (**theControl).contrlData ) {
  305.     
  306.         HUnlock( (**theControl).contrlData );
  307.         
  308.     }
  309.  
  310. #if !defined(powerc) && !defined (__powerc)        // Don't bother setting up registers if PowerPC
  311.     RestoreA4();
  312. #endif
  313.     
  314. }
  315.  
  316. /******************************************************************************
  317.  
  318.     This procedure will setup you control when you are ready to allocate it.
  319.     It needs to be placed with the code up above (static pascal long MyControl)
  320.   
  321. *******************************************************************************/
  322. void SetUpMyControl( CntlParam theParam )
  323. {
  324.     // store the CDEF UPP in the refCon of the control, the CDEF stub gets
  325.     // the address in the refCon and calls that UPP for CDEF messages
  326.     
  327.     myMain.hControl = NewControl(    theParam.theWindow, 
  328.                                     &theParam.cntlRect, 
  329.                                     theParam.title, 
  330.                                     theParam.visible, 
  331.                                     theParam.initialValue, 
  332.                                     theParam.min, 
  333.                                     theParam.max, 
  334.                                     theParam.cntlType, 
  335.                                     (long)NewControlDefProc( MyControl ) );
  336. }
  337.  
  338. /******************************************************************************
  339.  
  340.   Draw the control. Check to see if it's active and if so, what part to draw.
  341.   Also you need to check to see if the control is horizontal or vertical and
  342.   can we draw in color.
  343.   
  344. *******************************************************************************/
  345. void    DrawMyControl( ControlHandle theControl, short part )
  346. {
  347.     Rect            cntlRect, thumbRect, arrowLT, arrowRB, trackRect;
  348.     short            cntlHilite, vCenter, hCenter;
  349.     RgnHandle        arrow;
  350.     RGBColor        theColor;
  351.     Point            mousePnt;        
  352.     MyCntlDataHan    myData;
  353.     
  354.     // retrieve the part information from the control's data field.
  355.     myData = (MyCntlDataHan)(**theControl).contrlData;
  356.     
  357.     // Did we retrieve the data?
  358.     if( myData != nil ) {
  359.     
  360.         // It worked, Alrighty then...
  361.     
  362.         // set up some variables
  363.         cntlRect     = (**theControl).contrlRect;
  364.         cntlHilite    = (**theControl).contrlHilite;
  365.         thumbRect     = (**myData).thumbRect;
  366.         arrowLT     = (**myData).arrowLT;
  367.         arrowRB     = (**myData).arrowRB;
  368.         trackRect    = (**myData).trackRect;
  369.         
  370.         // determine the centers for drawing. I haven't checked to see if I'm
  371.         // drawing a vertical or horizontal control. You will need to do this.
  372.         vCenter    = ( cntlRect.bottom - cntlRect.top ) / 2;
  373.         hCenter = ( cntlRect.right - cntlRect.left ) / 2;
  374.         
  375.  
  376.         // Determine what the hilite state of the control is
  377.         if( cntlHilite == 255 )
  378.         {
  379.             // the control is inactive. Draw accordingly
  380.             SetForeColor( GREY_C );
  381.             FrameRect( &cntlRect );
  382.             FrameRect( &arrowLT );
  383.             FrameRect( &arrowRB );
  384.             CalcMyThumbPosition( theControl, &thumbRect );
  385.             FrameRect( &thumbRect );
  386.             ColorNormal();
  387.             
  388.         } else {
  389.             
  390.             // ok, so the control is active. now what part should we draw
  391.             switch( part )
  392.             {
  393.                 //draw the entire control
  394.                 case 0:
  395.                     // ok first thing's first, let's erase the control. I'm checking to see
  396.                     // what the control's owner's (window) content color is.  Just to be nice.
  397.                     GetWinBackColor( (**theControl).contrlOwner, &theColor );
  398.                     RGBBackColor( &theColor );
  399.                     EraseRect( &cntlRect );
  400.         
  401.                     //------------------------------------------------
  402.                     // Draw left arrow
  403.                     //
  404.                     SetForeColor( GREY_B );
  405.                     PaintRect( &arrowLT );
  406.                     //--- add hilites and shadows
  407.                     HiliteAndShadow( WHITE_COLOR, GREY_E, 0, arrowLT );
  408.                     FrameRect( &arrowLT );
  409.                     //--- add the black arrows. check to see if we are horz or vert
  410.                     if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top ) {
  411.                     
  412.                         // we are horizontal
  413.                         DrawMyArrow( 0, arrowLT );
  414.                         
  415.                     } else {
  416.                     
  417.                         // we are vertical
  418.                         DrawMyArrow( 1, arrowLT );
  419.                         
  420.                     }
  421.                     
  422.                     //------------------------------------------------
  423.                     // Draw right arrow
  424.                     //
  425.                     SetForeColor( GREY_B );
  426.                     PaintRect( &arrowRB );
  427.                     //--- add hilites and shadows
  428.                     HiliteAndShadow( WHITE_COLOR, GREY_E, 0, arrowRB );
  429.                     FrameRect( &arrowRB );
  430.                     //--- add the black arrows. check to see if we are horz or vert
  431.                     if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top ) {
  432.                     
  433.                         // we are horizontal
  434.                         DrawMyArrow( 2, arrowRB );
  435.                         
  436.                     } else {
  437.                         
  438.                         // we are vertical
  439.                         DrawMyArrow( 3, arrowRB );
  440.                         
  441.                     }
  442.                     
  443.                     
  444.                     //------------------------------------------------
  445.                     // Draw the track part and the thumb. We put these
  446.                     // together because we might have to erase an old thumb position.
  447.                     //
  448.                     DrawMyThumb( theControl, 0 );
  449.                     break;
  450.                     
  451.                     
  452.                     
  453.                 case 20: // inUpButton
  454.                     //------------------------------------------------
  455.                     //     Let's erase the arrow's rect. Agin I'm getting the content color
  456.                     //    of the controls owner. (the window we're in)
  457.                     //
  458.                     GetWinBackColor( (**theControl).contrlOwner, &theColor );
  459.                     RGBBackColor( &theColor );
  460.                     EraseRect( &arrowLT );
  461.                     
  462.                     GetMouse( &mousePnt );
  463.                     if( PtInRect( mousePnt, &arrowLT ) && Button()) {
  464.                     
  465.                         //------------------------------------------------
  466.                         // Draw left arrow - inverted
  467.                         //
  468.                         SetForeColor( GREY_E );
  469.                         PaintRect( &arrowLT );
  470.                         //--- add hilites and shadows
  471.                         HiliteAndShadow( GREY_H, GREY_B, 0, arrowLT );
  472.                         FrameRect( &arrowLT );
  473.                         //--- add the arrows. check to see if we are horz or vert
  474.                         if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top ) {
  475.                         
  476.                             // we are horizontal
  477.                             DrawMyArrow( 0, arrowLT );
  478.                             
  479.                         } else {
  480.                         
  481.                             // we are vertical
  482.                             DrawMyArrow( 1, arrowLT );
  483.                             
  484.                         }
  485.                         
  486.                     } else {
  487.                     
  488.                         //------------------------------------------------
  489.                         // Draw left arrow - normal
  490.                         //
  491.                         SetForeColor( GREY_B );
  492.                         PaintRect( &arrowLT );
  493.                         //--- add hilites and shadows
  494.                         HiliteAndShadow( WHITE_COLOR, GREY_E, 0, arrowLT );
  495.                         FrameRect( &arrowLT );
  496.                         //--- add the arrows. check to see if we are horz or vert
  497.                         if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top ) {
  498.                         
  499.                             // we are horizontal
  500.                             DrawMyArrow( 0, arrowLT );
  501.                             
  502.                         } else {
  503.                         
  504.                             // we are vertical
  505.                             DrawMyArrow( 1, arrowLT );
  506.                             
  507.                         }
  508.                     
  509.                     }
  510.                     ColorNormal();
  511.                     break;
  512.                     
  513.                     
  514.                     
  515.                     
  516.                 case 21: //inDownButton
  517.                     //------------------------------------------------
  518.                     //     Let's erase the arrow's rect. Again I'm getting the content color
  519.                     //    of the controls owner. (the window we're in)
  520.                     //
  521.                     GetWinBackColor( (**theControl).contrlOwner, &theColor );
  522.                     RGBBackColor( &theColor );
  523.                     EraseRect( &arrowRB );
  524.                     
  525.                     //________________________________________________
  526.                     //    We need to determine how we should draw the arrows. Is the user
  527.                     //    clicking on them or is it normal? If it is being clicked on then
  528.                     //    we should check where the mouse is and if the button is down. This
  529.                     //    will determine if we draw the control inverted or not.
  530.                     //
  531.                     GetMouse( &mousePnt );
  532.                     if( PtInRect( mousePnt, &arrowRB ) && Button()) {
  533.                     
  534.                         //------------------------------------------------
  535.                         // Draw right arrow - inverted
  536.                         //
  537.                         SetForeColor( GREY_E );
  538.                         PaintRect( &arrowRB );
  539.                         //--- add hilites and shadows
  540.                         HiliteAndShadow( GREY_H, GREY_B, 0, arrowRB );
  541.                         FrameRect( &arrowRB );
  542.                         //--- add the black arrows. check to see if we are horz or vert
  543.                         if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top ) {
  544.                         
  545.                             // we are horizontal
  546.                             DrawMyArrow( 2, arrowRB );
  547.                             
  548.                         } else {
  549.                             
  550.                             // we are vertical
  551.                             DrawMyArrow( 3, arrowRB );
  552.                             
  553.                         }
  554.                     
  555.                     } else {
  556.                         
  557.                         //------------------------------------------------
  558.                         // Draw right arrow - normal
  559.                         //
  560.                         SetForeColor( GREY_B );
  561.                         PaintRect( &arrowRB );
  562.                         //--- add hilites and shadows
  563.                         HiliteAndShadow( WHITE_COLOR, GREY_E, 0, arrowRB );
  564.                         FrameRect( &arrowRB );
  565.                         //--- add the black arrows. check to see if we are horz or vert
  566.                         if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top ) {
  567.                         
  568.                             // we are horizontal
  569.                             DrawMyArrow( 2, arrowRB );
  570.                             
  571.                         } else {
  572.                             
  573.                             // we are vertical
  574.                             DrawMyArrow( 3, arrowRB );
  575.                             
  576.                         }
  577.                         
  578.                     }
  579.                     ColorNormal();
  580.                     break;
  581.                     
  582.                 
  583.                 
  584.                 case 22: // inPageUp
  585.                 case 23: // inPageDown
  586.                     //------------------------------------------------
  587.                     // All we need to do here is determine if we are to the left or right
  588.                     // ( or top or bottom ) of the thumb's position.  Then create a rect
  589.                     // who's left or right ( top or bottom ) is that of the thumb's.
  590.                     //
  591.                     
  592.                     // get the current mouse position
  593.                     GetMouse( &mousePnt );
  594.                     
  595.                     // need to find if we are a vert or horz control. Only need to do this when
  596.                     // we are inverting the control. We need to draw the entire control when
  597.                     // asked to draw it normally. Why?!? Because when we invert it we create
  598.                     // Hilites and shadows which need to be erased.
  599.                     if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top ) {
  600.                     
  601.                         // we are horizontal
  602.                         
  603.                         // find out where our current thumb is located ( real corrdinates )
  604.                         CalcMyThumbPosition( theControl, &thumbRect );
  605.                         
  606.                         // where is the mouse? on the right or the left?
  607.                         if( mousePnt.h <= thumbRect.left ) {
  608.                             trackRect.right = thumbRect.left;
  609.                         } else {
  610.                             trackRect.left = thumbRect.right - 1;
  611.                         }
  612.                         
  613.                     } else {
  614.                         
  615.                         // we are a vertical control
  616.  
  617.                         // find out where our current thumb is located ( real corrdinates )
  618.                         CalcMyThumbPosition( theControl, &thumbRect );
  619.                         
  620.                         // where is the mouse? on the top or the bottom?
  621.                         if( mousePnt.v <= thumbRect.top ) {
  622.                             trackRect.bottom = thumbRect.top + 1;
  623.                         } else {
  624.                             trackRect.top = thumbRect.bottom - 1;
  625.                         }
  626.                     }
  627.                         
  628.                     // now figure out how to draw it. ( inverted or normal )
  629.                     // and check to see if the are in the track portion or not.
  630.                     if( PtInRect( mousePnt, &trackRect ) && Button()) {
  631.                     
  632.                         //------------------------------------------------
  633.                         // Draw the trackRect part ( not the thumb ) - inverted
  634.                         //
  635.                         InvertRect( &trackRect );
  636.                         SetForeColor( GREY_C );
  637.                         PaintRect( &trackRect );
  638.                         //--- add hilites and shadows
  639.                         HiliteAndShadow( GREY_G, WHITE_COLOR, 0, trackRect );
  640.                         FrameRect( &trackRect );
  641.                         
  642.                     } else {
  643.                     
  644.                         //------------------------------------------------
  645.                         // Draw the track part ( not the thumb ) - normal
  646.                         //
  647.                         SetForeColor( GREY_A );
  648.                         PaintRect( &trackRect );
  649.                         //--- add hilites and shadows
  650.                         HiliteAndShadow( GREY_C, WHITE_COLOR, 0, trackRect );
  651.                         FrameRect( &trackRect );
  652.                         
  653.                         CalcMyThumbPosition( theControl, &thumbRect );
  654.                         SetForeColor( GREY_B );
  655.                         PaintRect( &thumbRect );
  656.                         //--- add hilites and shadows
  657.                         HiliteAndShadow( WHITE_COLOR, GREY_E, 0, thumbRect );
  658.                         FrameRect( &thumbRect );
  659.                         
  660.                     }
  661.                     break;
  662.                     
  663.                 
  664.                 case 129: // inThumb
  665.                     // We don't have to do this here. Actually i don't believe it
  666.                     // will even get called here. This has it's own routine I believe.
  667.                     break;
  668.                     
  669.             }
  670.             
  671.         }
  672.     } else {
  673.     
  674.         // we had some problem retrieving our data
  675.         ReportError( "\pCouldn't retrieve data for drawing the control." );
  676.         
  677.     }
  678. }
  679.  
  680. /******************************************************************************
  681.  
  682.   Test to see what part the user clicked in. We already checked to see if the
  683.   mouse click was actually inside the control. It was, so now see what part
  684.   they clicked in and return a number for it. Apple has a set of variables that
  685.   is uses for standard controls. So since our control is a variation of a normal
  686.   slider we'll use their variables. Check out FindControl() in IM or THINK Ref.
  687.   
  688. *******************************************************************************/
  689. short    TestMyControlParts( ControlHandle theControl, Point clickPnt )
  690. {
  691.     Rect            pageLeft, pageRight, realThumbRect, cntlRect;
  692.     MyCntlDataHan    myData;
  693.     
  694.     //    For our own refrence let's define our parts..
  695.     //
  696.     //    thumb        = inThumb         = 129
  697.     //    arrowLT     = inUpButton     = 20
  698.     //     arrowRB     = inDownButton    = 21
  699.     //    pageLeft    = inPageUp        = 22
  700.     //    pageRight    = inPageDown    = 23
  701.     
  702.     // ok let's get our stored data from the control's contrlData field
  703.     myData        = (MyCntlDataHan)(**theControl).contrlData; // force the data to form to our struct
  704.     
  705.     // set up the control's rectangle for testing
  706.     cntlRect = (**theControl).contrlRect;
  707.     
  708.     // we need to find out what the real thhumb on the control's rect is
  709.     CalcMyThumbPosition( theControl, &realThumbRect );
  710.     
  711.     // double check to make sure that in fact we have data to play with
  712.     if( myData != nil ) {
  713.         
  714.         // it worked. wow!
  715.         // now, all we do is test where exactly in the control the click was.
  716.         
  717.         //is it in the thumb?
  718.         if( PtInRect( clickPnt, &realThumbRect ) ) {
  719.             return( inThumb );
  720.         } else {
  721.         
  722.             // is it in one of the arrows?
  723.             if( PtInRect( clickPnt, &(**myData).arrowLT ) ) {
  724.                 return( inUpButton );
  725.             } else {
  726.             
  727.                 if( PtInRect( clickPnt, &(**myData).arrowRB ) ) {
  728.                     return( inDownButton );
  729.                 } else {
  730.                 
  731.                     // is it in the trackRect somewhere?
  732.                     if( PtInRect( clickPnt, &(**myData).trackRect ) ) {
  733.                         
  734.                         // we have to see if it's to the right of the thumb or left of it. Or if we are
  735.                         // a vertical control the top and the bottom.
  736.                         
  737.                         if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top ) {
  738.                         
  739.                             // we have a horizontal control
  740.                             
  741.                             pageLeft = pageRight = (**myData).trackRect;
  742.                             pageLeft.right = realThumbRect.left;
  743.                             pageRight.left = realThumbRect.right;
  744.                             
  745.                         } else {
  746.                         
  747.                             // we have a vertical control
  748.                             
  749.                             pageLeft = pageRight = (**myData).trackRect;
  750.                             pageLeft.bottom = realThumbRect.top;
  751.                             pageRight.top = realThumbRect.bottom;
  752.                             
  753.                         }
  754.                         
  755.                         if( PtInRect( clickPnt, &pageLeft ) ) {
  756.                             return( inPageUp );
  757.                         } else {
  758.                             if( PtInRect( clickPnt, &pageRight ) ) {
  759.                                 return( inPageDown );
  760.                             }
  761.                         }
  762.                         
  763.                     } else {
  764.                     
  765.                         // hey it wasn't in any of my rects. how'd that happ'n?
  766.                         ReportError( "\pTesting points and couldn't find point within any of my parts." );
  767.                     }
  768.                 }
  769.             }
  770.         }
  771.         
  772.     } else {
  773.         
  774.         // retrieving the control's data failed.
  775.         ReportError( "\pCouldn't retrieve control data while testing the control." );
  776.         
  777.     }
  778.     
  779. }
  780.  
  781. /******************************************************************************
  782.     
  783.     When we recieve a 'initCntl' message in our control we use this procedure
  784.     to set up the 'contrlData' field in our control.  This data is used to
  785.     store information about our control that we will use throughout it's life.
  786.     
  787. *******************************************************************************/
  788. void    InitMyControl( ControlHandle theControl )
  789. {
  790.     Rect            cntlRect, thumbRect, arrowLT, arrowRB, trackRect, slopRect;
  791.     short            cntl_high = 0, cntl_wide = 0;
  792.     MyCntlDataHan    myData;
  793.     
  794.     // set our cntlRect to equal the control's rect.
  795.     cntlRect = (**theControl).contrlRect;
  796.     
  797.     // we need to determine if we have a vertical or horizontal control
  798.     if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top ) {
  799.         
  800.         // we have a horizontal control
  801.         
  802.         // the first thing to do is determine the height of our control to make square arrows buttons
  803.         cntl_high = cntlRect.bottom - cntlRect.top;
  804.         
  805.         // first we'll set the arrow buttons.
  806.         SetRect( &arrowLT, cntlRect.left, cntlRect.top, cntlRect.left + cntl_high, cntlRect.bottom );
  807.         SetRect( &arrowRB, cntlRect.right - cntl_high, cntlRect.top, cntlRect.right, cntlRect.bottom );
  808.         
  809.         // Now we'll set the track's rectangle. Take the cntlRect - the arrow buttons.
  810.         trackRect = cntlRect;
  811.         trackRect.left = arrowLT.right - 1; // we want them to overlap.
  812.         trackRect.right = arrowRB.left + 1; // we want them to overlap.
  813.         
  814.         // Now we'll set the thumb rect up. We don't have to actually set the rect
  815.         // to it's exact position, but just the size for now.
  816.         //    Right = width
  817.         //  Bottom = height (cntlRect's height - 2, so it's inset little.)
  818.         SetRect( &thumbRect, 0, 0, MY_THUMB_LENGTH, cntl_high - 2 );
  819.         
  820.     } else {
  821.     
  822.         // we have a vertical control
  823.         
  824.         // the first thing to do is determine the width of our control to make square arrows buttons
  825.         cntl_wide = cntlRect.right - cntlRect.left;
  826.         
  827.         // first we'll set the arrow buttons.
  828.         SetRect( &arrowLT, cntlRect.left, cntlRect.top, cntlRect.right, cntlRect.top + cntl_wide );
  829.         SetRect( &arrowRB, cntlRect.left, cntlRect.bottom - cntl_wide, cntlRect.right, cntlRect.bottom );
  830.         
  831.         // Now we'll set the track's rectangle. Take the cntlRect - the arrow buttons.
  832.         trackRect = cntlRect;
  833.         trackRect.top = arrowLT.bottom - 1;
  834.         trackRect.bottom = arrowRB.top + 1;
  835.         
  836.         // Now we'll set the thumb rect up. We don't have to actually set the rect
  837.         // to it's exact position, but just the size for now.
  838.         //    Right = height (cntlRect's height - 2, so it's inset little.)
  839.         //  Bottom = width
  840.         SetRect( &thumbRect, 0, 0, cntl_wide - 2, MY_THUMB_LENGTH );
  841.     }
  842.     
  843.     // we need to set the size of the handle we are using
  844.     myData = (MyCntlDataHan)NewHandle( sizeof( MyCntlData ) );
  845.     
  846.     if( myData != nil ) {
  847.         
  848.         // now store our handle in the contrlData field in the control record
  849.         (**theControl).contrlData  = (Handle)myData;
  850.         
  851.         // now simply copy this information into our handle.
  852.         (**myData).cntlRect        = cntlRect;
  853.         (**myData).thumbRect    = thumbRect;
  854.         (**myData).arrowLT        = arrowLT;     // left or top arrow
  855.         (**myData).arrowRB        = arrowRB;    // right or bottom arrow
  856.         (**myData).trackRect    = trackRect;
  857.         
  858.     } else {
  859.     
  860.         // We had any error. Respond what error had occured.
  861.         ReportError( "\pCouldn't allocate area for the data handle." );
  862.         
  863.     }
  864.         
  865. }
  866.  
  867. /******************************************************************************
  868.     
  869.     This procedure will get called when we recieve a 'dispCntl' in the
  870.     param of our control.  All we need to do is distroy any data that we
  871.     initialized earlier in the 'initCntl' procedure.
  872.     
  873. *******************************************************************************/
  874. void     DisposeMyControl( ControlHandle theControl )
  875. {
  876.     MyCntlDataHan    myData;
  877.     
  878.     if( theControl != nil ) {
  879.     
  880.         // Get the handle to the control's data.
  881.         myData = (MyCntlDataHan)(**theControl).contrlData;
  882.         
  883.         if( myData != nil ) {
  884.         
  885.             // lock the structs data.
  886.             HLock( (Handle) myData );
  887.             
  888.             // dispose of our data handle and set the contrlData field to nil.
  889.             DisposeHandle(     (Handle) myData );
  890.             (**theControl).contrlData = nil;
  891.             
  892.         } else {
  893.             
  894.             // error occurred trying to retreive info from the control's data field.
  895.             ReportError( "\pCouldn't retrieve control data information." );
  896.             
  897.         }
  898.     } else {
  899.     
  900.         // For some reason we didn't get a true control handle passed to us
  901.         ReportError( "\pTried to extract data information, but was passed a bad control handle." );
  902.     
  903.     }
  904. }
  905.  
  906. /******************************************************************************
  907.  
  908.     Out Control recieved a 'thumbCntl' message. We need to fill in the parameters
  909.     of the controls limit rect and slop rect and axis.
  910.     
  911.       By the way, CntlParm is a struct defined on top. We use it here to set up
  912.       or force the data that lies within 'param' to match our requirements. 
  913.   
  914. *******************************************************************************/
  915. void    FillCntlParameters( ControlHandle theControl, CntlParmPtr *param )
  916. {
  917.     Rect            limitRect, slopRect, cntlRect, realThumbRect;
  918.     short            axis;
  919.     Point            mousePnt;
  920.     MyCntlDataHan    myData;
  921.     
  922.     // You may be asking yourself, "What exactly are we doing here?"
  923.     // Well we are setting some parameters, that Apple has provided
  924.     // us control definition makers, to allow some helpful human
  925.     // interaction. ( At least I think so ).
  926.     //
  927.     // The limitRect gives us the mouse coordinates on entry. On exit 
  928.     // this rect should contain the control track rectangle. The slopRect
  929.     // gives us an area in which the user can drag outside the control's
  930.     // rectangle in which the control will still respond. If the user moves
  931.     // outside this 'slop rectangle' then the control will return to it's
  932.     // previous state. The axis constrain the drag movement depending on the
  933.     // setting. noContraint = 0 ( no constraint ), hAxisOnly = 1 ( horizontal only ),
  934.     // vAxisOnly = 2 ( vertical only ).
  935.     
  936.     // extract data from the contrlData field and form to our struct.
  937.     myData        = (MyCntlDataHan)(**theControl).contrlData; 
  938.     
  939.     // let's get the true or real thumb rect ( the one that gets drawn )
  940.     CalcMyThumbPosition( theControl, &realThumbRect );
  941.     
  942.     // set the cntlRect to match the control's rectangle
  943.     cntlRect = (**theControl).contrlRect;
  944.     
  945.     // extract the mouse down points from param
  946.     mousePnt.h = (**param).limitRect.left;
  947.     mousePnt.v = (**param).limitRect.top;
  948.     
  949.     if( myData != nil ) {
  950.     
  951.         // now let's determine if we are using a horz or vert control
  952.         if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top ) {
  953.         
  954.             // we have ourselves a horizontal control
  955.             
  956.             // adjust the limitRect to take in account where the user clicked within the thumb
  957.             (**param).limitRect.left = (**myData).arrowLT.right + ( mousePnt.h - realThumbRect.left );
  958.             (**param).limitRect.right = (**myData).arrowRB.left - ( (realThumbRect.right-1) - mousePnt.h );
  959.             
  960.             // now let's adjust the slopRect slightly, increase it by 20 pixels...
  961.             (**param).slopRect = (**myData).trackRect;
  962.             InsetRect( &(**param).slopRect, -20, -20 );
  963.             
  964.             // then extend it's edges about 100 pixels. This normally gives the correct feel.
  965.             (**param).slopRect.left -= 100;
  966.             (**param).slopRect.right += 100;
  967.             
  968.             // set up the axis for a horizontal control
  969.             (**param).axis = hAxisOnly;
  970.         
  971.         } else {
  972.         
  973.             // we have a vertical control.
  974.             
  975.             // adjust the limitRect to take in account where the user clicked within the thumb
  976.             (**param).limitRect.top = (**myData).arrowLT.bottom + ( mousePnt.v - realThumbRect.top );
  977.             (**param).limitRect.bottom = (**myData).arrowRB.top - ( (realThumbRect.bottom-1) - mousePnt.v );
  978.             
  979.             // now let's adjust the slopRect slightly, increase it by 20 pixels...
  980.             (**param).slopRect = (**myData).trackRect;
  981.             InsetRect( &(**param).slopRect, -20, -20 );
  982.             
  983.             // then extend it's edges about 100 pixels. This normally gives the correct feel.
  984.             slopRect.top -= 100;
  985.             slopRect.bottom += 100;
  986.             
  987.             // set up the axis for the control
  988.             (**param).axis = vAxisOnly;
  989.             
  990.         }
  991.         
  992.     } else {
  993.     
  994.         // we had an error retreiving data form the control
  995.         ReportError( "\pWe couldn't extract data from the control while calculating the parameters." );
  996.             
  997.     }
  998. }
  999.  
  1000. /******************************************************************************
  1001.  
  1002.   This is a fairly straight forward procedure. All we have to do is find the position of
  1003.   the thumb on the track and return a rect to match these values. Easy shmeazy. All
  1004.   we are doing here is calculating the "Real Thumb Rect" for drawing.
  1005.   
  1006. *******************************************************************************/
  1007. void    CalcMyThumbPosition( ControlHandle theControl, Rect *realThumbRect )
  1008. {
  1009.     long            min, max, value, dist;
  1010.     short            cntl_high, cntl_wide;
  1011.     Rect            cntlRect, trackRect;
  1012.     MyCntlDataHan    myData;
  1013.     
  1014.     // Do some initial setting up
  1015.     cntlRect    = (**theControl).contrlRect;
  1016.     min             = (**theControl).contrlMin;
  1017.     max             = (**theControl).contrlMax;
  1018.     value        = (**theControl).contrlValue;
  1019.     myData        = (MyCntlDataHan)(**theControl).contrlData; // force the data to form to our struct
  1020.     
  1021.     // double check to make sure that in fact we have data to play with
  1022.     if( myData != nil ) {
  1023.         
  1024.         // it worked! cool...
  1025.         
  1026.         // make sure the value isn't greater or less than max & min
  1027.         if( value > max ) {
  1028.             value = max;
  1029.         } else {
  1030.             if( value < min ) {
  1031.                 value = min;
  1032.             }
  1033.         }
  1034.         
  1035.         // retrieve the track rect from our data
  1036.         trackRect = (**myData).trackRect;
  1037.         
  1038.         // Do we have a horizontal or vertical control???
  1039.         if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top )
  1040.         {
  1041.             // We have horizontal control
  1042.             
  1043.             // We need to set the trackRect to take in account of the thumb width.
  1044.             // We do this so we don't overwrite part of the arrow when we are drawing.
  1045.             trackRect.left  += ( MY_THUMB_LENGTH / 2 ) + 1;
  1046.             trackRect.right -= ( MY_THUMB_LENGTH / 2 ) + 1;
  1047.             
  1048.             // determine how wide our track rect is and then calculate the distance we move.
  1049.             cntl_wide = trackRect.right - trackRect.left;
  1050.             dist = trackRect.left + (((max + value) * cntl_wide) / (max - min)) - ( MY_THUMB_LENGTH / 2 );
  1051.             
  1052.             // we know that the top and bottom of our thumb rect will be the same as the
  1053.             // control's rect (basically). It's actually inset 1 pixel to fit inside the track.
  1054.             (*realThumbRect).top     = cntlRect.top + 1;
  1055.             (*realThumbRect).bottom = cntlRect.bottom - 1;
  1056.             
  1057.             // now set the left and right to the correct coordinates for drawing.
  1058.             (*realThumbRect).left  = (**myData).thumbRect.left + dist;
  1059.             (*realThumbRect).right = (**myData).thumbRect.right + dist;
  1060.             
  1061.         } else {
  1062.             
  1063.             // We have a vertical control
  1064.             
  1065.             // We need to set the trackRect to take in account of the thumb width.
  1066.             // We do this so we don't overwrite part of the arrow when we are drawing.
  1067.             trackRect.top       += ( MY_THUMB_LENGTH / 2 ) + 1;
  1068.             trackRect.bottom -= ( MY_THUMB_LENGTH / 2 ) + 1;
  1069.             
  1070.             // determine how tall our track rect is and then calculate the distance we move.
  1071.             cntl_high = trackRect.bottom - trackRect.top;
  1072.             dist = trackRect.top + (((max + value) * cntl_high) / (max - min)) - ( MY_THUMB_LENGTH / 2 );
  1073.             
  1074.             // we know that the left and right of our thumb rect will be the same as the
  1075.             // control's rect (basically). It's actually inset 1 pixel to fit inside the track.
  1076.             (*realThumbRect).left  = cntlRect.left + 1;
  1077.             (*realThumbRect).right = cntlRect.right - 1;
  1078.             
  1079.             // now set the top and bottom to the correct coordinates for drawing.
  1080.             (*realThumbRect).top     = (**myData).thumbRect.top + dist;
  1081.             (*realThumbRect).bottom = (**myData).thumbRect.bottom + dist;
  1082.             
  1083.         }
  1084.     } else {
  1085.     
  1086.         // we had a problem getting our data. bummer!
  1087.         ReportError( "\pTrying to calculate thumb postion and couldn't access data field." );
  1088.         
  1089.     }
  1090. }
  1091.  
  1092. /******************************************************************************
  1093.  
  1094.   This procedure will draw the black arrows located in my arrow buttons.
  1095.   you pass it a variable that tells which way the arrow should point and a
  1096.   rect in which the arrow will be drawn. Fairly straight forward.
  1097.   
  1098.   0 = points left
  1099.   1 = points up
  1100.   2 = points right
  1101.   3 = points down
  1102.   
  1103. *******************************************************************************/
  1104. void    DrawMyArrow( short var, Rect theRect )
  1105. {
  1106.     RgnHandle        arrow;
  1107.     short            center;
  1108.     
  1109.     arrow = NewRgn();
  1110.     OpenRgn();
  1111.     
  1112.     switch( var ) {
  1113.         
  1114.         case 0:  // points left
  1115.             center = ( theRect.bottom - theRect.top ) / 2;
  1116.             MoveTo( theRect.left + 5, theRect.top + center );
  1117.             LineTo( theRect.right - 6, theRect.top + 2 );
  1118.             LineTo( theRect.right - 6, theRect.bottom - 4 );
  1119.             LineTo( theRect.left + 5, theRect.bottom - center );
  1120.             break;
  1121.             
  1122.         case 1:  // points up
  1123.             center = ( theRect.right - theRect.left ) / 2;
  1124.             MoveTo( theRect.left + 1, theRect.bottom - 6 );
  1125.             LineTo( theRect.left + center - 1, theRect.top + 5 );
  1126.             LineTo( theRect.right - 3, theRect.bottom - 6 );
  1127.             LineTo( theRect.left + 1, theRect.bottom - 6 );
  1128.             break;
  1129.             
  1130.         case 2:  // points right
  1131.             center = ( theRect.bottom - theRect.top ) / 2;
  1132.             MoveTo( theRect.right - 5, theRect.top + center + 1 );
  1133.             LineTo( theRect.left + 6, theRect.top + 3 );
  1134.             LineTo( theRect.left + 6, theRect.bottom - 4 );
  1135.             LineTo( theRect.right - 5, theRect.bottom - center - 1 );
  1136.             break;
  1137.             
  1138.         case 3:  // points down
  1139.             center = ( theRect.right - theRect.left ) / 2;
  1140.             MoveTo( theRect.left + 2, theRect.top + 6 );
  1141.             LineTo( theRect.left + center, theRect.bottom - 5 );
  1142.             LineTo( theRect.right - 4, theRect.top + 6 );
  1143.             LineTo( theRect.left + 2, theRect.top + 6 );
  1144.             break;
  1145.     
  1146.     }
  1147.     
  1148.     CloseRgn( arrow );
  1149.     FillRgn( arrow, &qd.black );
  1150.     DisposeRgn( arrow );
  1151. }
  1152.  
  1153. /******************************************************************************
  1154.  
  1155.     Custom Dragging Procedure - not needed if you use default dragging. 
  1156.                                 ( when TrackControl is passed a zero for
  1157.                                   the tracking procedure )
  1158.     
  1159.     Used to move the indicator or thumb.
  1160.                                   
  1161.     This procedure will show the user the interaction when they click on the
  1162.     thumb part of our control.  All we are going to do is drag the thumb's
  1163.     rect around using the drag grey rgn routine untill the user let's up on the
  1164.     mouse. For kicks and grins we will also draw the control's value above the
  1165.     indicator. We also will use the parameters that we set for slop rect and limit rect.
  1166.     
  1167. *******************************************************************************/
  1168. void    DragMyThumb( ControlHandle theControl, Point mousePnt )
  1169. {
  1170.     RgnHandle        thumbRgn;
  1171.     Rect            slopRect, limitRect, realThumbRect, cntlRect;
  1172.     long            newPoint;
  1173.     MyCntlDataHan    myData;
  1174.     short            value, axis;
  1175.     
  1176.     // set up some variables..
  1177.     myData        = (MyCntlDataHan)(**theControl).contrlData; // force the data to form to our struct
  1178.     cntlRect    = (**theControl).contrlRect;
  1179.     
  1180.     // double check to make sure that in fact we have data to play with
  1181.     if( myData != nil ) {
  1182.     
  1183.         // it worked, hurray.
  1184.         
  1185.         // let's get the true or real thumb rect ( the one that gets drawn )
  1186.         CalcMyThumbPosition( theControl, &realThumbRect );
  1187.         
  1188.         // this is where we are declaring the parameters for dragging.
  1189.         slopRect = limitRect = (**myData).trackRect;
  1190.         
  1191.         // now let's determine if we are using a horz or vert control
  1192.         if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top ) {
  1193.         
  1194.             // we have ourselves a horizontal control
  1195.             
  1196.             // adjust the limitRect to take in account where the user clicked within the thumb
  1197.             limitRect.left = (**myData).arrowLT.right + ( mousePnt.h - realThumbRect.left );
  1198.             limitRect.right = (**myData).arrowRB.left - ( (realThumbRect.right-1) - mousePnt.h );
  1199.             
  1200.             // now let's adjust the slopRect slightly, increase it by 20 pixels...
  1201.             InsetRect( &slopRect, -20, -20 );
  1202.             
  1203.             // then extend it's edges about 100 pixels. This normally gives the correct feel.
  1204.             slopRect.left -= 100;
  1205.             slopRect.right += 100;
  1206.             
  1207.             // define our axis that we will use to constrain the indicators movement.
  1208.             axis = hAxisOnly;
  1209.         
  1210.         } else {
  1211.         
  1212.             // we have a vertical control.
  1213.             
  1214.             // adjust the limitRect to take in account where the user clicked within the thumb
  1215.             limitRect.top = (**myData).arrowLT.bottom + ( mousePnt.v - realThumbRect.top );
  1216.             limitRect.bottom = (**myData).arrowRB.top - ( (realThumbRect.bottom-1) - mousePnt.v );
  1217.             
  1218.             // now let's adjust the slopRect slightly, increase it by 20 pixels...
  1219.             InsetRect( &slopRect, -20, -20 );
  1220.             
  1221.             // then extend it's edges about 100 pixels. This normally gives the correct feel.
  1222.             slopRect.top -= 100;
  1223.             slopRect.bottom += 100;
  1224.             
  1225.             // define our axis that we will use to constrain the indicators movement.
  1226.             axis = vAxisOnly;
  1227.             
  1228.         }
  1229.         
  1230.         // we've been asked to only move the indicator
  1231.     
  1232.         // now do our dragging. first declare a new rgn to copy out thumb rect into.
  1233.         // then this gets passed to the DragGrayRgn() procedure.  It actually handles the dragging.
  1234.         thumbRgn = NewRgn();
  1235.         RectRgn( thumbRgn, &realThumbRect );
  1236.         
  1237.         // This is the actual routine to drag the indicator. For a more detailed explanation
  1238.         // look on page 4-96 in IM:Toolbox Essentails or use Think Refrence.
  1239.         newPoint = DragGrayRgn( thumbRgn, mousePnt, &limitRect, &slopRect, axis, nil );
  1240.         
  1241.         // now determine if the thumb did in fact move. if DragGrayRgn() returns a value of
  1242.         // 0x80008000 it means that the user realeased the mouse outside the sloprect. HiWord
  1243.         // of newPoint is the vertical dist moved where as the LoWord is horz dist moved.
  1244.         
  1245.         if( newPoint != 0x80008000 ) {
  1246.             
  1247.             // It was released inside our control. newPoint will contain the horizontal and vertical 
  1248.             // ditance moved.
  1249.             
  1250.             mousePnt.h = LoWord( newPoint );
  1251.             mousePnt.v = HiWord( newPoint );
  1252.             ConvertPtToVal( theControl, mousePnt, &value );
  1253.             SetCtlValue( theControl, value );
  1254.             DrawMyThumb( theControl, 1 );
  1255.             DrawValueInThumb( theControl, value );
  1256.             
  1257.         } else {
  1258.         
  1259.             // it was released outside the slopRect. Do nothing
  1260.             ReportError( "\pYou released the mouse outside the slop Rect." );
  1261.             
  1262.         }
  1263.         
  1264.         DisposeRgn( thumbRgn );
  1265.         
  1266.     } else {
  1267.     
  1268.         // it didn't work
  1269.         ReportError( "\pCouldn't retrieve control data while dragging the control's thumb." );
  1270.         
  1271.     }
  1272. }
  1273.  
  1274. /******************************************************************************
  1275.  
  1276.  
  1277.  
  1278.     Custom Dragging Procedure - not needed if you use default dragging. 
  1279.                                 ( when TrackControl is passed a zero for
  1280.                                   the tracking procedure )
  1281.     
  1282.     Used to move the entire control.
  1283.                                   
  1284.     This procedure is only used when the user is given the ability to move
  1285.     the entire control. I really haven't thought of any reason to do this, but
  1286.     if it's something that is implicated in your code then here it is.
  1287.     
  1288.     limitRect - will most likely be the control's ownern's content region.
  1289.     slopRect  - will be whatever value you think should be used. for tutorial
  1290.                 purposes I'll use the window's content region inset -20
  1291.     axis      - I'll assume that you would want to give them complete freedom.
  1292.                 No constraint.
  1293.     
  1294. *******************************************************************************/
  1295. void    DragMyControl( ControlHandle theControl, Point mousePnt )
  1296. {
  1297.     Rect            slopRect, limitRect, cntlRect;
  1298.     short            axis;
  1299.     WindowPtr        cntlWindow;
  1300.     
  1301.     // set up some variables..
  1302.     cntlRect    = (**theControl).contrlRect;
  1303.     cntlWindow  = (**theControl).contrlOwner;
  1304.         
  1305.     // this is where we are declaring the parameters for dragging.
  1306.     slopRect = limitRect = (*cntlWindow).portRect;
  1307.     
  1308.     // now let's determine if we are using a horz or vert control
  1309.     if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top ) {
  1310.     
  1311.         // we have ourselves a horizontal control
  1312.         
  1313.         // adjust the limitRect to take in account where the user clicked within the control
  1314.         limitRect.left = cntlRect.left + mousePnt.h;
  1315.         limitRect.right = cntlRect.right - mousePnt.h;
  1316.         
  1317.         // now let's adjust the slopRect slightly, increase it by 20 pixels...
  1318.         InsetRect( &slopRect, -20, -20 );
  1319.         
  1320.         // define our axis that we will use to constrain the indicators movement.
  1321.         axis = noConstraint;
  1322.     
  1323.     } else {
  1324.     
  1325.         // we have a vertical control.
  1326.         
  1327.         // adjust the limitRect to take in account where the user clicked whithin the control
  1328.         limitRect.top = cntlRect.top + mousePnt.v;
  1329.         limitRect.bottom = cntlRect.bottom - mousePnt.v;
  1330.         
  1331.         // now let's adjust the slopRect slightly, increase it by 20 pixels...
  1332.         InsetRect( &slopRect, -20, -20 );
  1333.         
  1334.         // define our axis that we will use to constrain the indicators movement.
  1335.         axis = noConstraint;
  1336.         
  1337.     }
  1338.         
  1339.     // This is the actual routine used to drag the entire control for a more detailed
  1340.     // exlpaination look on page 5-99 IM:Toolbox Essentails or use Think Refrence.
  1341.     DragControl( theControl, mousePnt, &limitRect, &slopRect, axis );
  1342.     
  1343. }
  1344. /******************************************************************************
  1345.  
  1346.     All this procedure does is draw the thumb depending on the current control
  1347.     value. Fairly straight forward procedure. It will get called after the
  1348.     user drags the thumb and if the control recieves a draw entire control msg.
  1349.     
  1350.     I added a simply variable to tell my drawing procedure if I'm drawing for
  1351.     custom dragging or default dragging.  Since I didn't do anything to wild
  1352.     for my dragging I'm using this instead.  If the value is 0 then it just
  1353.     draws the thumb normally. If anything else it draws it with the value in
  1354.     the middle.
  1355.  
  1356. *******************************************************************************/
  1357. void     DrawMyThumb( ControlHandle theControl, Boolean var )
  1358. {
  1359.     Rect            realThumbRect, trackRect;
  1360.     MyCntlDataHan    myData;
  1361.     
  1362.     // set up some variables..
  1363.     myData        = (MyCntlDataHan)(**theControl).contrlData; // force the data to form to our struct
  1364.     
  1365.     // double check to make sure that in fact we have data to play with
  1366.     if( myData != nil ) {
  1367.     
  1368.         // it worked we have data to play with
  1369.         
  1370.         // first draw the track ( to erase any old thumb positions )
  1371.         trackRect = (**myData).trackRect;
  1372.         
  1373.         SetForeColor( GREY_A );
  1374.         PaintRect( &trackRect );
  1375.         
  1376.         //--- add hilites and shadows
  1377.         HiliteAndShadow( GREY_C, WHITE_COLOR, 0, trackRect );
  1378.         FrameRect( &trackRect );
  1379.                         
  1380.         //--- since we now know how large our thumb is, where should we draw it?
  1381.         //--- the position is stored in the control's value field.
  1382.         CalcMyThumbPosition( theControl, &realThumbRect );
  1383.         SetForeColor( GREY_B );
  1384.         PaintRect( &realThumbRect );
  1385.         
  1386.         //--- add hilites and shadows
  1387.         HiliteAndShadow( WHITE_COLOR, GREY_E, 0, realThumbRect );
  1388.         FrameRect( &realThumbRect );
  1389.         
  1390.         if( var != 0 ) {
  1391.             
  1392.             // draw the text in the middle
  1393.             DrawValueInThumb( theControl, (**theControl).contrlValue );
  1394.         
  1395.         }
  1396.         
  1397.     } else {
  1398.     
  1399.         // we couldn't obtain the data for some reason.
  1400.         ReportError( "\pCouldn't access control data while attempting to draw the thumb." );
  1401.         
  1402.     }
  1403. }
  1404.  
  1405. /******************************************************************************
  1406.  
  1407.     All we do here is calculate our thumb rect, convert to a region and copy it
  1408.     into param (which is asking for a region handle) This is done so that the
  1409.     user can drag our thumb.
  1410.  
  1411. *******************************************************************************/
  1412. void    CalcMyThumbRgn( ControlHandle theControl, RgnHandle *param )
  1413. {
  1414.     Rect                realThumbRect;
  1415.         
  1416.     // first let's find the real thumb rect
  1417.     CalcMyThumbPosition( theControl, &realThumbRect );
  1418.     
  1419.     // now just convert it into a rgn (using the pointer to param )
  1420.     RectRgn( *param, &realThumbRect );
  1421. }
  1422.  
  1423. /******************************************************************************
  1424.  
  1425.     Our control was sent a 'posCntl' in the message parameter. param contains the
  1426.     horizontal and vertical offset to move your indicator from it's current
  1427.     position. ( vert = HiWord, horz = LoWord ).
  1428.     
  1429.     We will calculate the new setting and then redraw the control and update
  1430.     it's control value.
  1431.     
  1432.     This one through me for a loop. I wasn't recieving a posCntl for the life of
  1433.     me. I figured out that I wasn't setting the param correctly in FillCntlParameters().
  1434.     I wasn't forcing the data within param to my struct 'CntlParms' correctly. I
  1435.     was forgetting to typeCast the param when sending it to my function.  It's
  1436.     the little things like that that will drive you crazy.
  1437.  
  1438. *******************************************************************************/
  1439. void    PositionMyCntl( ControlHandle theControl, Point mousePnt )
  1440. {
  1441.     short        value;
  1442.  
  1443.     // All we have to do is calculate the new thumb value and then
  1444.     // use CalcMyThumbPosition() to figure out the new location
  1445.     // of the thumb. TrackControl() will handle the draggin if things
  1446.     // are set up correctly in FillCntlParameters().
  1447.     
  1448.     // First convert the point given to us into a new value
  1449.     ConvertPtToVal( theControl, mousePnt, &value );
  1450.     
  1451.     // set the control's value to this new value
  1452.     SetCtlValue( theControl, value );
  1453.     
  1454.     // Now just redraw the indicator or thumb.
  1455.     DrawMyThumb( theControl, 0 );
  1456. }
  1457.  
  1458. /******************************************************************************
  1459.  
  1460.     This procedure will take a point that is within the track Rectangle
  1461.     and convert it to a value.
  1462.  
  1463. *******************************************************************************/
  1464. void     ConvertPtToVal( ControlHandle theControl, Point newPoint, short *value )
  1465. {
  1466.     Rect            trackRect, cntlRect, realThumbRect;
  1467.     short            currThumbCenter, newThumbCenter, trackWidth;
  1468.     long            min, max, newValue;
  1469.     MyCntlDataHan    myData;
  1470.     
  1471.     // extract the control data and form to our struct.
  1472.     myData        = (MyCntlDataHan)(**theControl).contrlData; 
  1473.     
  1474.     // double check to make sure that in fact we have data to play with
  1475.     if( myData != nil ) {
  1476.     
  1477.         // set up some initial variables
  1478.         trackRect = (**myData).trackRect;
  1479.         cntlRect  = (**theControl).contrlRect;
  1480.         min       = (**theControl).contrlMin;
  1481.         max       = (**theControl).contrlMax;
  1482.         
  1483.         if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top ) {
  1484.         
  1485.             // it's a horizontal control
  1486.             
  1487.             // take in account the thumb length for the edges of the track. I added one
  1488.             // because it had a tendancy to round down and not set my complete value.
  1489.             trackRect.right -= ( MY_THUMB_LENGTH / 2 ) + 1;
  1490.             trackRect.left  += ( MY_THUMB_LENGTH / 2 ) + 1;
  1491.             
  1492.             // we need to obtain the center of the current thumb position
  1493.             CalcMyThumbPosition( theControl, &realThumbRect );
  1494.             currThumbCenter = realThumbRect.left + (( realThumbRect.right - realThumbRect.left ) / 2 );
  1495.             
  1496.             // determine the thumbs new center with the given offset.
  1497.             newThumbCenter = currThumbCenter + newPoint.h;
  1498.             
  1499.             // make sure the point isn't outside the track now that we made adjustments.
  1500.             if( newThumbCenter < trackRect.left ) {
  1501.             
  1502.                 newThumbCenter = trackRect.left;
  1503.                 
  1504.             } else {
  1505.             
  1506.                 if( newThumbCenter > trackRect.right ) { 
  1507.                 
  1508.                     newThumbCenter = trackRect.right;
  1509.                     
  1510.                 }
  1511.             }
  1512.             
  1513.             // find the width of our track rect
  1514.             trackWidth = trackRect.right - trackRect.left;
  1515.             
  1516.             // calculate our new value.
  1517.             newValue = min + ( ( max - min ) * ( newThumbCenter - trackRect.left ) ) / trackWidth;
  1518.             
  1519.         } else {
  1520.         
  1521.             // it's a vertical control
  1522.             
  1523.             // take in account the thumb length for the edges of the track.
  1524.             trackRect.bottom -= ( MY_THUMB_LENGTH / 2 ) + 1;
  1525.             trackRect.top    += ( MY_THUMB_LENGTH / 2 ) + 1;
  1526.             
  1527.             // we need to obtain the center of the current thumb position
  1528.             CalcMyThumbPosition( theControl, &realThumbRect );
  1529.             currThumbCenter = realThumbRect.top + (( realThumbRect.bottom - realThumbRect.top ) / 2 );
  1530.             
  1531.             // determine the thumbs new center with the given offset.
  1532.             newThumbCenter = currThumbCenter + newPoint.v;
  1533.             
  1534.             // make sure the point isn't outside the track now that we made adjustments.
  1535.             if( newThumbCenter < trackRect.top ) {
  1536.             
  1537.                 newPoint.v = trackRect.top;
  1538.                 
  1539.             } else {
  1540.             
  1541.                 if( newThumbCenter > trackRect.bottom ) { 
  1542.                 
  1543.                     newPoint.v = trackRect.bottom;
  1544.                     
  1545.                 }
  1546.             }
  1547.             
  1548.             // find the height of our track rect
  1549.             trackWidth = trackRect.bottom - trackRect.top;
  1550.             
  1551.             // calculate our new value.
  1552.             newValue = min + ( ( max - min ) * ( newThumbCenter - trackRect.top ) ) / trackWidth;
  1553.             
  1554.         }
  1555.         
  1556.         *value = newValue;
  1557.         
  1558.     } else {
  1559.     
  1560.         // We had problems extracting the data from the control's data field
  1561.         ReportError( "\pCouldn't access the control's data while converting a point to a value." );
  1562.         
  1563.     }
  1564. }
  1565.  
  1566. /******************************************************************************
  1567.  
  1568.     Custom Dragging Procedure - not needed if you use default dragging. 
  1569.                                 ( when TrackControl is passed a zero for
  1570.                                   the tracking procedure )
  1571.     
  1572.     Used to draw the controls value within the thumb.
  1573.                                   
  1574.     This is just to show an example of how you could use custom dragging. This
  1575.     is anything to fancy. Will just take the contol's value. Make sure it will
  1576.     fit within our thumb and draw it in its center. For the sake of simplicity
  1577.     we will not do this for a vertical control.
  1578.     
  1579.     In reality you could use this for default draggin also, but I justed wanted
  1580.     to show you something. I'm using a standard drag procedure for my custom
  1581.     dragging so you really don't notice any big difference. This at least shows
  1582.     some difference.
  1583.  
  1584. *******************************************************************************/
  1585. void    DrawValueInThumb( ControlHandle theControl, long value )
  1586. {
  1587.     Rect            realThumbRect, cntlRect;
  1588.     Str15            numString, errString = "\p???";    // will never be greater than 4 digits with our values.
  1589.     short            center, strWidth;                // used to draw our text.
  1590.     GrafPtr            thePort;                        // used to get font info
  1591.     short            txFont, txSize, txFace, txMode;    // to store current font info.
  1592.     RGBColor        theColor;
  1593.     
  1594.     // first it helps to set the cntlRect
  1595.     cntlRect = (**theControl).contrlRect;
  1596.     
  1597.     if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top ) {
  1598.         
  1599.         // we have a horizontal control
  1600.         
  1601.         // we do this to find out current font settings.
  1602.         GetPort( &thePort );
  1603.         
  1604.         // Set up some variables and also find & change the current font information
  1605.         NumToString( value, numString );
  1606.         cntlRect = (**theControl).contrlRect;
  1607.         txFont = (*thePort).txFont;
  1608.         txSize = (*thePort).txSize;
  1609.         txFace = (*thePort).txFace;
  1610.         txMode = (*thePort).txMode;
  1611.         GetBackColor( &theColor );
  1612.         TextFont( 9 );
  1613.         TextSize( 9 );
  1614.         TextFace( 0 );
  1615.         TextMode( 0 );     // for this to work and erase the background we need to 
  1616.                         // be sure to set the background color to the thumb color.
  1617.                         
  1618.         SetBackColor( GREY_B );        // this is the thumbs color
  1619.         
  1620.         // find the real thumb position
  1621.         CalcMyThumbPosition( theControl, &realThumbRect );
  1622.         
  1623.         // let's double check to make sure our value is bigger than four digits
  1624.         if( numString[0] > 0x04 ) {
  1625.         
  1626.             // we can't have that happen
  1627.             BlockMove( &errString[0], &numString[0], 4 );
  1628.             
  1629.         }
  1630.         
  1631.         center   = realThumbRect.left + (( realThumbRect.right - realThumbRect.left ) / 2 );
  1632.         strWidth = StringWidth( numString );
  1633.         
  1634.         MoveTo( center - ( strWidth / 2 ), realThumbRect.bottom - 4 );
  1635.         DrawString( numString );
  1636.         
  1637.         // redraw hilites and shadows on the thumb because we overWrite them slightly
  1638.         HiliteAndShadow( WHITE_COLOR, GREY_E, 0, realThumbRect );
  1639.         FrameRect( & realThumbRect );
  1640.         
  1641.         // be nice and return everything back to the way they were.
  1642.         TextFont( txFont );
  1643.         TextSize( txSize );
  1644.         TextFace( txFace );
  1645.         TextMode( txMode );
  1646.         RGBBackColor( &theColor );
  1647.         
  1648.     } else {
  1649.     
  1650.         // we have a vertical control so let's not bother
  1651.         
  1652.     }
  1653. }
  1654.  
  1655.  
  1656.  
  1657.  
  1658.  
  1659.  
  1660.  
  1661.  
  1662.